package com.ontheroad.mysql.path.service;

import cn.modoumama.page.PageObject;
import cn.modoumama.service.base.impl.BaseServiceImpl;
import com.alibaba.fastjson.JSON;
import com.ontheroad.api.request.PathRequest;
import com.ontheroad.api.response.Response;
import com.ontheroad.collect.modle.CollectModel;
import com.ontheroad.mysql.collect.mapper.CollectMapper;
import com.ontheroad.mysql.path.event.PathEvent;
import com.ontheroad.mysql.path.mapper.PathSystemMapper;
import com.ontheroad.mysql.path.mapper.PathUserMapper;
import com.ontheroad.mysql.sport.mapper.SportMapper;
import com.ontheroad.path.model.PathSystemModel;
import com.ontheroad.path.model.PathUserModel;
import com.ontheroad.path.model.Point;
import com.ontheroad.path.service.PathService;
import com.ontheroad.sport.model.SportModel;
import com.ontheroad.utils.DateUtil;
import com.spatial4j.core.context.SpatialContext;
import com.spatial4j.core.distance.DistanceUtils;
import com.spatial4j.core.shape.Rectangle;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * Created by kedong on 2017/6/29 0029.
 */
@Service
@Transactional
public class PathServiceImpl extends BaseServiceImpl<PathUserModel, Long> implements PathService, ApplicationContextAware {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private SportMapper sportMapper;

    @Autowired
    private PathUserMapper mapper;

    @Autowired
    private CollectMapper collectMapper;

    @Autowired
    private PathSystemMapper systemMapper;

    private ApplicationContext applicationContext;

    @Autowired
    public void setMapper(PathUserMapper mapper) {
        setGenericMapper(mapper);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * 添加轨迹
     *
     * @param request
     * @return
     * @throws Exception
     */
    @Override
    public Response addPath(PathRequest request) throws Exception {
        Long userId = request.getUserId();
        // 保存运动信息
        SportModel sportModel = new SportModel();
        sportModel.setUserid(userId.intValue());
        sportModel.setDuration(request.getDuration());
        Date endTime = DateUtil.stringTodate(request.getEndTime(), "yyyy-MM-dd HH:mm");
        sportModel.setEndTime(endTime);
        sportModel.setKilometre(request.getKilometre());
        sportModel.setType(request.getType());
        sportMapper.insertModel(sportModel);

        // 保存轨迹信息
        PathUserModel pathUserModel = new PathUserModel();
        pathUserModel.setUserid(userId);
        pathUserModel.setSportid(sportModel.getId().longValue());
        pathUserModel.setAltitude(request.getAltitude());
        pathUserModel.setStart(request.getStart());
        pathUserModel.setEnd(request.getEnd());
        pathUserModel.setName(request.getName());
        pathUserModel.setKilometre(request.getKilometre());
        pathUserModel.setHeight(request.getHeight());
        pathUserModel.setTime(request.getTime());
        pathUserModel.setSpeed(request.getSpeed());
        pathUserModel.setCreateTime(new Date());
        pathUserModel.setType(request.getType());
        // TODO 生成缩略图
//        pathUserModel.setPathIconUrl("todo");
        mapper.insertModel(pathUserModel);

        String points = request.getPoints();
        List<Point> pointList = JSON.parseArray(points, Point.class);
        List<Point> list = new ArrayList<>();
        for (Point point : pointList) {
            point.setPathUserId(pathUserModel.getId().intValue());
            point.setUserId(userId.intValue());

            list.add(point);
            // 每1000条数据入库一次
            if (list.size() >= 1000) {
                mapper.batchSavePoints(list);
                list.clear();
            }
        }
        if (list.size() > 0) {
            mapper.batchSavePoints(list);
        }

        Response response = Response.SUCCESS();
        response.addResultData("pathId", pathUserModel.getId());
        response.addResultData("sportId", sportModel.getId());
        return response;
    }

    @Override
    public void addPoint(String gpxStr, Integer userId, Integer pathUserId, Integer pathSysId) {
        applicationContext.publishEvent(new PathEvent("保存轨迹点", gpxStr, userId, pathUserId, pathSysId));
    }

    @Override
    public Response getSystemPathList(PathRequest request) throws Exception {
        // 分页
        PageObject po = new PageObject();
        po.setCurrPage(request.getPageNum());
        po.setPageSize(request.getPageSize());
        RowBounds rowBounds = new RowBounds(po.getOffset(), po.getPageSize());
        List<PathSystemModel> systemModels = systemMapper.findModelsByCondition(po.getCondition(), rowBounds);
        for (PathSystemModel systemModel : systemModels) {
            systemModel.setGeojson(null);
            systemModel.setGpx(null);
        }
        Response response = Response.SUCCESS();
        response.addResultData("systemPaths", systemModels);
        return response;
    }

    @Override
    public Response getUserPathDetail(PathRequest request) throws Exception {
        Long pathId = Long.valueOf(request.getPathId());
        Long userId = request.getUserId();
        PathUserModel pathUserModel = mapper.getObjectById(pathId);
        if (pathUserModel == null) {
            return Response.FAILED("轨迹不存在");
        }
        Map<String, Object> map = new HashMap<>();
        map.put("pathid", pathId);
        map.put("userid", userId);
        List<CollectModel> collectModels = collectMapper.findModelsByCondition(map);
        pathUserModel.setIsCollect(collectModels != null && collectModels.size() > 0);
        List<Point> points = mapper.findPointsByPathUserId(pathUserModel.getId().intValue());
        pathUserModel.setPoints(points);

        Response response = Response.SUCCESS();
        Long sportId = pathUserModel.getSportid();
        if(sportId != null){
            SportModel sport = sportMapper.getObjectById(sportId.intValue());
            response.addResultData("sport", sport);
        }
        response.addResultData("userPath", pathUserModel);
        return response;
    }

    @Override
    public Response getUserPathList(PathRequest request) throws Exception {
        Long userId = request.getUserId();
        // 分页
        PageObject po = new PageObject();
        po.setCurrPage(request.getPageNum());
        po.setPageSize(request.getPageSize());
        po.getCondition().put("userid", userId);
        po.getCondition().put("orderByClause", "create_time desc");
        RowBounds rowBounds = new RowBounds(po.getOffset(), po.getPageSize());
        List<PathUserModel> pathUserModels = mapper.findModelsByCondition(po.getCondition(), rowBounds);
        Response response = Response.SUCCESS();
        response.addResultData("userPaths", pathUserModels);
        return response;
    }

    @Override
    public Response getSystemPathDetail(PathRequest request) throws Exception {
        Integer pathId = request.getPathId();
        PathSystemModel systemModel = systemMapper.getObjectById(Long.valueOf(pathId));

        systemModel.setGeojson(null);
        systemModel.setGpx(null);

        List<Point> points = mapper.findPointsByPathSysId(systemModel.getId().intValue());
        systemModel.setPoints(points);

        Response response = Response.SUCCESS();
        response.addResultData("systemPath", systemModel);
        return response;
    }

    @Override
    public List<Point> findPointsByPathUserId(Long pathUserId) {
        return mapper.findPointsByPathUserId(pathUserId.intValue());
    }

    @Override
    public List<PathUserModel> findNearPath(Double lat, Double lng) {
        // 收缩半斤范围
        int radius = 1;
        SpatialContext geo = SpatialContext.GEO;
        Rectangle rectangle = geo.getDistCalc().calcBoxByDistFromPt(
                geo.makePoint(lng, lat), radius * DistanceUtils.KM_TO_DEG, geo, null);
        double lngMin = rectangle.getMinX();
        double lngMax = rectangle.getMaxX();
        double latMin = rectangle.getMinY();
        double latMax = rectangle.getMaxY();

        // 分页
        PageObject po = new PageObject();
        RowBounds rowBounds = new RowBounds(po.getOffset(), po.getPageSize());
        // 查新轨迹ID
        List<Integer> userPathIds = mapper.findNearPath(lngMin, lngMax, latMin, latMax, rowBounds);
        List<PathUserModel> pathUserModelList = new ArrayList<>();
        if (userPathIds != null && userPathIds.size() > 0) {
            // 根据ID查询轨迹
            pathUserModelList = mapper.findPathByIds(userPathIds);
        }
        return pathUserModelList;
    }

}
